<?php

if (!defined("PATH_HD"))
    exit('No direct script access allowed');

// .-----------------------------------------------------------------------------------
// |  Software: [HDPHP framework]
// |   Version: 2013.01
// |      Site: http://www.hdphp.com
// |-----------------------------------------------------------------------------------
// |    Author: 向军 <houdunwangxj@gmail.com>
// | Copyright (c) 2012-2013, http://houdunwang.com. All Rights Reserved.
// |-----------------------------------------------------------------------------------
// |   License: http://www.apache.org/licenses/LICENSE-2.0
// '-----------------------------------------------------------------------------------
/**
 * 应用处理处理类
 * @package     core
 * @author      后盾向军 <houdunwangxj@gmail.com>
 */
final class App {

    //应用组路径
    static private $pathAppGroup;
    //应用路径
    static private $pathApp;

    /**
     * 应用初始处理
     * @access public
     * @return void
     */
    static public function run() {
       
        self::init(); //初始化运行环境
       
        self::loadPaths(); //根据配置文件动态加载的系统文件
        self::setBaseUrl(); //基本url常量
        self::loadCoreConfigLanguage(); //加载核心配置文件与语言包
        self::formatRequest(); //如果开启自动转义,去除转义
        self::getAppGroupPath(); //设置应用路径
        self::loadAppGroupConfig(); //加载应用组配置
      
        self::getAppPath(); //设置PATH_APP
        self::setPathConst(); //设置目录常量
        self::loadAppConfig(); //加载应用配置文件
        //如果定义DEBUG常量则开启调试
        if (defined("DEBUG") && DEBUG) {
            C("DEBUG", DEBUG);
        }
         
        C("DEBUG") && debug::start("app_start");
       
        self::setTempConst(); //设置临时目录常量
        self::createApp(); //创建测试应用
        self::setTplConst(); //设置模板常量
       
        self::language(); //加载语言包
        self::ajaxCloseDebug(); //ajax时关闭调试
        self::setCharset(); //设置字符集
        self::sessionSet(); //自定义SESSION处理
        self::compileAppGroupFile(); //项目核心文件编译缓存
        self::compileAppFile(); //模块核心文件编译缓存
        self::compileCoreFile(); //编译核心文件
        
        self::apprun(); //项目开始
          
        self::saveQueryLimit(); //记录缓存或SQL查询次数
        C("DEBUG") && Debug::show("app_start", "app_end"); //显示调试结果
        Log::save(); //记录日志
    }

    /**
     * 初始化环境
     * @access private
     * @return void
     */
    static private function init() {
        @ini_set('memory_limit', '128M');
        @ini_set("register_globals", "off");
        @ini_set('magic_quotes_runtime', 0);
        define("MAGIC_QUOTES_GPC", @get_magic_quotes_gpc() ? true : false ); //是否开启系统转义

        define('REQUEST_METHOD', $_SERVER['REQUEST_METHOD']);
        define('IS_GET', REQUEST_METHOD == 'GET' ? true : false);
        define('IS_POST', REQUEST_METHOD == 'POST' ? true : false);
        define('IS_PUT', REQUEST_METHOD == 'PUT' ? true : false);
        define('IS_DELETE', REQUEST_METHOD == 'DELETE' ? true : false);
        if (function_exists("spl_autoload_register")) {
            spl_autoload_register(array(__CLASS__, "autoload")); //注册自动载入函数
        }
        set_error_handler(array("ExceptionHD", "error"), E_ALL); //设置错误处理函数
        set_exception_handler(array("ExceptionHD", "exception")); //设置异常
    }

    /**
     * 动态加载的系统文件
     * @access private
     * @return void
     */
    static private function loadPaths() {
        auto_load_system_file(include PATH_HD_CORE . '/paths.php'); //动态加载的系统文件
    }

    /**
     * 基本url常量
     * @access private
     * @return void
     */
    static private function setBaseUrl() {
        $_SERVER['REQUEST_URI'] = rtrim($_SERVER['REQUEST_URI'], '/');
        $_SERVER['DOCUMENT_ROOT'] = str_replace("\\", "/", $_SERVER['DOCUMENT_ROOT']);
        $_SERVER['SCRIPT_FILENAME'] = str_replace("\\", "/", $_SERVER['SCRIPT_FILENAME']);
        if (!strstr($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME'])) {
            $_SERVER['REQUEST_URI'] = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['PHP_SELF']);
        }
        if (isset($_SERVER['PATH_INFO'])) {
            $_SERVER['PATH_INFO'] = trim($_SERVER['PATH_INFO'], '/');
        }
        $host = $_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
        $url = isset($_SERVER['REDIRECT_URL']) ? str_replace($_SERVER['REQUEST_URI'], '', $_SERVER['REDIRECT_URL']) : $_SERVER['SCRIPT_NAME'];
        define("__HOST__", "http://" . trim($host, '/')); //域名
        $documentRoot = trim(str_ireplace($_SERVER['DOCUMENT_ROOT'], '', dirname($_SERVER['SCRIPT_FILENAME']).'/'), '/');
        // var_dump($_SERVER['DOCUMENT_ROOT']);
        // var_dump(dirname($_SERVER['SCRIPT_FILENAME']));

        $root = empty($documentRoot) ? "" : '/' . $documentRoot;
        // echo $documentRoot;
        // exit;
        define("__ROOT__", __HOST__ . $root); //主页URL根地址地址
        define("__HDPHP__", __HOST__ . '/' . trim(str_ireplace($_SERVER['DOCUMENT_ROOT'], "", PATH_HD), '/'));
        define("__STATIC__", __ROOT__ . '/static');
        define("__HDPHP_DATA__", __HDPHP__ . '/data');
        define("__HDPHP_TPL__", __HDPHP__ . '/libs/tpl');
        define("__HDPHP_PLUGIN__", __HDPHP__ . '/plugin');
        define("__WEB__", __HOST__ . $url); //带入口文件名的常量

    }

    /**
     * 加载核心配置文件与语言包
     * @access private
     * @return void
     */
    static private function loadCoreConfigLanguage() {
        C(include PATH_HD_CONFIG . '/config.php'); //加载框架核心配置文件
        C("VAR_APP", "a"); //应用APP的GET参数名
        L(include PATH_HD_LANGUAGE . '/utf8.php');
    }

    /**
     * 用户数据转义处理
     * @access private
     * @return void
     */
    static private function formatRequest() {
        if (!MAGIC_QUOTES_GPC) {
            return;
        }
        $_GET = stripslashes_d($_GET);
        $_POST = stripslashes_d($_POST);
        $_REQUEST = stripslashes_d($_REQUEST);
        $_COOKIE = stripslashes_d($_COOKIE);
    }

    /**
     * 设置PATH_APP_GROUP
     * @access private
     * @return void
     */
    static private function getAppGroupPath() {
        if (defined("APP_GROUP_PATH")) {
            self::$pathAppGroup = rtrim(str_replace("\\", "/", APP_GROUP_PATH), '/');
        } elseif (defined("APP_GROUP")) {
            self::$pathAppGroup = PATH_ROOT . '/' . APP_GROUP;
        } else {
            self::$pathAppGroup = PATH_ROOT;
        }
    }

    /**
     * 加载应用组配置文件
     * @access private
     * @return void
     */
    static private function loadAppGroupConfig() {
        //应用组配置
        if (defined("APP_GROUP")) {
            $common_config = self::$pathAppGroup . '/common/config/config.php';
            is_file($common_config) && C(include($common_config));
            Url::parseUrl();
        }
    }

    /**
     * 设置PATH_APP
     * @access private
     * @return void
     */
    static private function getAppPath() {
        $pathApp = ''; //应用路径
        $var_app = C("VAR_APP");
        if (defined("APP_PATH")) {
            $pathApp = rtrim(str_replace("\\", "/", APP_PATH), '/');
        } elseif (defined("APP")) {
            $pathApp = self::$pathAppGroup . '/' . APP;
        } elseif (!isset($_GET[$var_app]) && empty($_SERVER['PATH_INFO'])) {
            $pathApp = self::$pathAppGroup . '/index';
        } elseif (isset($_GET[$var_app])) {
            $pathApp = self::$pathAppGroup . '/' . $_GET[$var_app];
        } else {
            $pathinfo = rtrim($_SERVER['PATH_INFO'], '/');
            $path = explode(C("pathinfo_dli"), $pathinfo);
            foreach ($path as $k => $v) {
                if ($k == 0 && $v == $var_app) {
                    if (!isset($path[$k + 1])) {
                        header("Content-type:text/html;charset=utf-8");
                        error("URL中" . $var_app . "后连接应用名如:" . $var_app . '/admin 形式', false);
                    }
                    $pathApp = self::$pathAppGroup . '/' . $path[$k + 1];
                }
            }
            $pathApp = $pathApp ? $pathApp : self::$pathAppGroup . '/' . $path[0];
        }
        self::$pathApp = str_replace('\\', "/", $pathApp);
    }

    /**
     * 加载应用配置文件
     * @access private
     * @return void
     */
    static private function loadAppConfig() {
        //应用配置
        $app_config = self::$pathApp . '/config/config.php';
        is_file($app_config) && C(include($app_config));
        //如果应用组执行过Url::parseUrl()则应用不再执行
        defined("__APP__") || Url::parseUrl();
    }

    /**
     * 设置目录常量
     * @access private
     * @return void
     */
    static private function setPathConst() {
        define("PATH_APP_GROUP", self::$pathAppGroup); //应用组路径
        if (defined("APP_GROUP_PATH") && !defined("APP_GROUP")) {
            define("APP_GROUP", dirname(PATH_APP_GROUP));
        }
        define("PATH_COMMON_CONFIG", PATH_APP_GROUP . '/common/config');
        define("PATH_COMMON_LANGUAGE", PATH_APP_GROUP . '/common/language');
        define("PATH_COMMON_LIBS", PATH_APP_GROUP . '/common/libs');
        define("PATH_COMMON_MODEL", PATH_APP_GROUP . '/common/model');
        if (!is_dir(self::$pathApp)) {
            //如果没有临时文件夹或入口文件定义了APP或APP_NAME时创建应用目录
            if (!is_file(PATH_TEMP_BOOT) || APP_SET) {
                dir_create(self::$pathApp);
            } else {
                //开启调试模型显示创建应用按钮
                _404("访问" . __WEB__ . "失败，因为应用目录不存在，删除" . PATH_TEMP_BOOT . '文件后，系统会自动创建应用目录');
            }
        }
        define("PATH_APP", str_replace('\\', '/', realpath(self::$pathApp)));
        define("PATH_CONFIG", PATH_APP . '/config');
        define("PATH_LANGUAGE", PATH_APP . '/language');
        define("PATH_LIBS", PATH_APP . '/libs');
        define("PATH_CONTROL", PATH_APP . '/control');
        define("PATH_MODEL", PATH_APP . '/model');
    }

    /**
     * 设置应用临时目录常量
     * @access private
     * @return void
     */
    static private function setTempConst() {
        define("PATH_TEMP_APP_GROUP", defined("APP_GROUP") ? PATH_TEMP . '/Applications/' . APP_GROUP . '_G/' : PATH_TEMP . '/Applications/'); //应用组临时缓存目录
        define("PATH_TEMP_APP", PATH_TEMP_APP_GROUP . APP . '_A'); //应用运行临时文件目录路径
        define("PATH_TEMP_CACHE", PATH_TEMP_APP . '/cache'); //应用缓存文件夹
        define("PATH_TEMP_CONTROL", PATH_TEMP_APP . '/' . CONTROL . '_C'); //控制器运行临时文件目录路径
        define("PATH_TEMP_METHOD", PATH_TEMP_CONTROL . '/' . METHOD); //方法运行临时文件目录路径
        define("PATH_TEMP_TABLE", PATH_TEMP . '/table'); //表结构缓存目录路径
        define("PATH_TEMP_SELECT", PATH_TEMP_METHOD . '/select'); //查询结果缓存路径
        define("PATH_TEMP_COMPILE", PATH_TEMP_METHOD . '/compile'); //模板编译文件路径
        define("PATH_TEMP_TPL_CACHE", PATH_TEMP_METHOD . '/cache'); //模板静态缓存目录路径
    }

    /**
     * 创建测试应用
     * @access private
     * @return void
     */
    static private function createApp() {
        if (!is_dir(PATH_CONFIG)) {
            load_file(PATH_HD_CORE . '/createApp.php');
        }
    }

    /**
     * 设置模板常量
     * @access private
     * @return void
     */
    static private function setTplConst() {
        $tplDir = rtrim(C("TPL_DIR"), '/');
        if (empty($tplDir)) {
            $tplDir = 'tpl';
            C("TPL_DIR", $tplDir);
        }
        $template_dir = ''; //模板路径
        $style = C('TPL_STYLE') ? '/' . C('TPL_STYLE') : ''; //配置文件中模板风格
        if (strstr($tplDir, '/')) {
            $template_dir = $tplDir . $style;
        } else {
            $template_dir = PATH_APP . '/' . $tplDir . $style;
        }
        define("PATH_TPL", $template_dir);
        define("__TPL__", __HOST__ . '/' . trim(str_ireplace($_SERVER['DOCUMENT_ROOT'], '', PATH_TPL), '/')); //模版目录URL地址
        define("__PUBLIC__", __TPL__ . '/public');
        define("PATH_PUBLIC", PATH_TPL . '/public');
    }

    /**
     * 加载语言包
     * @access private
     * @return void
     */
    static private function language() {
        //应用组及应用语言包
        $language = C("LANGUAGE");
        $appGroupLang = PATH_COMMON_LANGUAGE . '/' . $language . '.php';
        $appLang = PATH_LANGUAGE . '/' . $language . '.php';
        if (defined("APP_GROUP") && is_file($appGroupLang)) {
            L(load_file($appGroupLang));
        }
        if (is_file($appLang)) {
            L(load_file($appLang));
        }
    }

    /**
     * ajax时关闭调试
     * @access private
     * @return void
     */
    static private function ajaxCloseDebug() {
        if (!C("debug_ajax") && C("DEBUG") && ajax_request()) {//异步时是否关闭调试模式
            C("debug", 0);
        }
    }

    /**
     * 设置基础字符集
     * @access private
     * @return void
     */
    static private function setCharset() {
        $charset = strtoupper(C("CHARSET")) == 'UTF8' ? "UTF-8" : strtoupper(C("CHARSET"));
        define("CHARSET", $charset);
        define("CHARSET_DB", str_replace("-", "", $charset));
    }

    /**
     * 自定义SESSION处理
     * 根据配置文件自定义SESSION处理，及是否自动开启SESSION
     * @access private
     * @return void
     */
    static private function sessionSet() {
        $sessionDriver = SessionFactory::factory();
        $sessionDriver->init();
        if (!ini_get("session.auto_start") && C("SESSION_AUTO")) {
            session_start();
        }
    }

    /**
     * 将项目及模块核心文件编译缓存
     * @access private
     * @return void
     */
    static private function compileAppGroupFile() {
        if (!defined('APP_GROUP')) {
            return;
        }
        $compileAppGroupFile = PATH_TEMP_APP_GROUP . 'APP_GROUP_' . APP_GROUP . '.php';
        //当生成编译文件且没开启DEBUG及编译目录是新的时候
        //且编译文件修改时间大于LIBS目录时
        if (!C("DEBUG") && COMPILE && file_exists($compileAppGroupFile)
                && filemtime(PATH_COMMON_LIBS) < filemtime($compileAppGroupFile)) {
            load_File($compileAppGroupFile);
            return;
        }
        if (C("DEBUG")) {
            $files = glob(PATH_COMMON_LIBS . '/*');
            if (!$files)
                return;
            foreach ($files as $v) {
                load_file($v);
            }
        } else {
            $files = glob(PATH_COMMON_LIBS . '/*');
            if (!$files)
                return;
            php_merge($files, $compileAppGroupFile);
            load_File($compileAppGroupFile);
        }
    }

    /**
     * 将项目及应用核心文件编译缓存
     * @access private
     * @return void
     */
    static private function compileAppFile() {
        $compileAppFile = PATH_TEMP_APP . '/APP_' . APP . '.php';
        //当生成编译文件且没开启DEBUG及编译目录是新的时候
        //且编译文件修改时间大于LIBS目录时
        if (!C("DEBUG") && COMPILE && file_exists($compileAppFile)
                && filemtime(PATH_LIBS) < filemtime($compileAppFile)) {
            load_File($compileAppFile);
            return;
        }
        if (C("DEBUG")) {
            $appFile = glob(PATH_LIBS . '/*');
            if (!$appFile)
                return;
            foreach ($appFile as $v) {
                load_file($v);
            }
        } else {
            $appFile = glob(PATH_LIBS . '/*');
            if (!$appFile)
                return;
            php_merge($appFile, $compileAppFile);
            load_file($compileAppFile);
        }
    }

    /**
     * 编译生成核心文件
     * @access private
     * @return void
     */
    static private function compileCoreFile() {
        //不生成编译文件
        if (!COMPILE) {
            return;
        } elseif (!is_file(PATH_TEMP_BOOT)) {
            $coreFile = PATH_HD_CORE . '/compileFiles.php'; //需要编译的文件
            $files = require $coreFile; //载入需要编译到compileFiles.phps中的文件列表
            php_merge($files, PATH_TEMP_BOOT); //合并且删除空格
        }
    }

    /**
     * 加载xxxControl控制器文件，运行项目
     * @access private
     * @return void
     */
    static private function apprun() {
        //设置时区
        if (function_exists("date_default_timezone_set")) {
            date_default_timezone_set(C("default_time_zone"));
        }
        $controlFile = rtrim(PATH_APP, '/') . '/control/' . CONTROL. C("CONTROL_FIX") . '.php';
        $control = control($controlFile); //执行动作
       
        if ($control) {
            //var_dump($control);die;
            call_user_func(array(&$control, METHOD));
           
        } else {
          
            //执行空控制器
            $emptyControlFile = rtrim(PATH_APP, '/') . '/control/Empty' . C("CONTROL_FIX") . '.php';
            $emptyControl = control($emptyControlFile);
            if ($emptyControl) {
                call_user_func(array(&$emptyControl, METHOD));
            } else {
                _404($controlFile . "控制器文件不存在或类名称定义错误(注意大小写)");
            }
        }
    }

    /**
     * 记录查询数：CACHE与DB_QUERY
     */
    static private function saveQueryLimit() {
        if (C("CACHE_SAVE")) {
            $cache = cache::init();
            $cache->options("save", false); //不记录
            $cache->set("hd_cache_get_hits", $cache->get("hd_cache_get_hits") + N("hd_cache_get_hits"));
            $cache->set("hd_cache_get_misses", $cache->get("hd_cache_get_misses") + N("hd_cache_get_misses"));
            $cache->set("hd_cache_set_hits", $cache->get("hd_cache_set_hits") + N("hd_cache_set_hits"));
            $cache->set("hd_cache_set_misses", $cache->get("hd_cache_set_misses") + N("hd_cache_set_misses"));
        }
    }

    /**
     * 自动载入函数
     * @access private
     * @return void
     */
    static private function autoload($className) {
        $control_fix = C("CONTROL_FIX");
        if (substr($className, -(strlen($control_fix))) == $control_fix && strlen($className) > strlen($control_fix)) {
            $controlInfo = get_control_file($className);
            $classFile = $controlInfo[0];
        } elseif (auto_load_system_file($className)) {
            $classFile = auto_load_system_file($className);
        } else {
            $classFile = PATH_HD . '/libs/class/' . $className . '.class.php';
        }
        load_file($classFile);
    }

}

?>